
#include "resmgr.h"
#include "uimgr.h"

//已删除部分注释

class CEmpty : public UIControl
{
public:
	CEmpty()
	{
		Type=CT_Empty;
		//Empty控件用作根节点，其尺寸覆盖整个窗口
		//大多数属性无意义，但是递归到根节点时会用到范围
		X=0;
		Y=0;
		Width=WinViewWidth;
		Height=WinViewHeight;
	}

	virtual ~CEmpty(){}
	virtual void Draw(){}
	virtual void Update(){}
	virtual int Notify(UIEvent_t UIEvent,PVOID Param1,PVOID Param2){return 0;}
};

void GUIManager::LoadFixResource()
{
	//目前所需资源较少，写着源码里，后面可能需要一个配置文件
	//这里没有保存相关指针，在资源管理器析构时一并释放
	ResMgr->LoadFontR(L"宋体-14",L"EngineRes\\宋体-14.png",L"EngineRes\\宋体-14-描边.png",14,1);
	ResMgr->LoadImageR(L"主背景",L"EngineRes\\背景.jpg",0,0,960,720);
	ResMgr->LoadScale9R(L"按钮Normal",L"EngineRes\\按钮.png",11,11,11,11);
	ResMgr->LoadScale9R(L"按钮Hover",L"EngineRes\\按钮Hover.png",11,11,11,11);
	ResMgr->LoadScale9R(L"按钮Push",L"EngineRes\\按钮Push.png",11,11,11,11);
	ResMgr->LoadScale9R(L"按钮Disable",L"EngineRes\\按钮Disable.png",11,11,11,11);

	ResMgr->LoadImageR(L"未选中Normal",L"EngineRes\\选择框按钮.png",0,0,16,16);
	ResMgr->LoadImageR(L"选中Normal",L"EngineRes\\选择框按钮.png",16,0,16,16);
	ResMgr->LoadImageR(L"未选中Hover",L"EngineRes\\选择框按钮.png",0,16,16,16);
	ResMgr->LoadImageR(L"选中Hover",L"EngineRes\\选择框按钮.png",16,16,16,16);
	ResMgr->LoadImageR(L"未选中Push",L"EngineRes\\选择框按钮.png",0,32,16,16);
	ResMgr->LoadImageR(L"选中Push",L"EngineRes\\选择框按钮.png",16,32,16,16);
	ResMgr->LoadImageR(L"未选中Disable",L"EngineRes\\选择框按钮.png",0,48,16,16);
	ResMgr->LoadImageR(L"选中Disable",L"EngineRes\\选择框按钮.png",16,48,16,16);

	ResMgr->LoadImageR(L"下拉Normal",L"EngineRes\\下拉按钮.png",0,0,16,16);
	ResMgr->LoadImageR(L"下拉Hover",L"EngineRes\\下拉按钮.png",0,16,16,16);
	ResMgr->LoadImageR(L"下拉Push",L"EngineRes\\下拉按钮.png",0,32,16,16);
	ResMgr->LoadImageR(L"下拉Disable",L"EngineRes\\下拉按钮.png",0,48,16,16);

	ResMgr->LoadImageR(L"滑块Normal",L"EngineRes\\滑动条滑块.png",0,0,15,15);
    ResMgr->LoadImageR(L"滑块Disable",L"EngineRes\\滑动条滑块.png",0,15,15,15);

	ResMgr->LoadScale9R(L"列表元素Normal",L"EngineRes\\列表元素Normal.png",5,5,5,5);
	ResMgr->LoadScale9R(L"列表元素Hover",L"EngineRes\\列表元素Hover.png",5,5,5,5);
	ResMgr->LoadScale9R(L"列表元素Select",L"EngineRes\\列表元素Select.png",5,5,5,5);
	ResMgr->LoadScale9R(L"列表元素SelHover",L"EngineRes\\列表元素SelectHover.png",5,5,5,5);

	ResMgr->LoadScale9R(L"Tab全_Normal",L"EngineRes\\Tab全_Normal.png",3,3,3,3);
	ResMgr->LoadScale9R(L"Tab左_Normal",L"EngineRes\\Tab左_Normal.png",3,3,3,3);
	ResMgr->LoadScale9R(L"Tab右_Normal",L"EngineRes\\Tab右_Normal.png",3,3,3,3);
	ResMgr->LoadScale9R(L"Tab中_Normal",L"EngineRes\\Tab中_Normal.png",3,3,3,3);	
	ResMgr->LoadScale9R(L"Tab全_Push",L"EngineRes\\Tab全_Push.png",3,3,3,3);
	ResMgr->LoadScale9R(L"Tab左_Push",L"EngineRes\\Tab左_Push.png",3,3,3,3);
	ResMgr->LoadScale9R(L"Tab右_Push",L"EngineRes\\Tab右_Push.png",3,3,3,3);
	ResMgr->LoadScale9R(L"Tab中_Push",L"EngineRes\\Tab中_Push.png",3,3,3,3);




	//......
}

GUIManager::GUIManager()
{
	DbgRecursiveNum=0;
	DisplayPage=NULL;
	InProcessState=FALSE;
	DeferDisplayPageId=-1;
	DeferDeletePageId=-1;
	PageWillChange=FALSE;
	PageWillDelete=FALSE;
	DeferDeleteControlPageId=-1;

	HoveredCtrl=NULL;
	PushedCtrl=NULL;
	FocusCtrl=NULL;
	TopmostCtrl=NULL;
	MouseX=0;
	MouseY=0;
	DragState=FALSE;
	DragBeginX=-1;
	DragBeginY=-1;
	KeyCtrlDown=FALSE;
	KeyShiftDown=FALSE;
	Freezed=FALSE;
	ClientWidth=WinViewWidth;
	ClientHeight=WinViewHeight;
}

GUIManager::~GUIManager()
{
	ResetInputState();
	DisplayPage=NULL;
	//分两轮处理，第一轮删除page上的全部控件，第二轮删除Page
	//控件删除时可能会用到Page，第一轮暂时不能删除Page（即使进行了erase也会出问题）
	std::map<int,PageData_t*>::iterator it;
	for (it=PageData.begin();it!=PageData.end();it++)
	{
		PageData_t* Page=it->second;
		RecursiveDeleteControl(Page,Page->Root);	
	}
	for (it=PageData.begin();it!=PageData.end();it++)
	{
		PageData_t* Page=it->second;
		delete Page;
	}
	PageData.clear();
}

GUIManager::PageData_t* GUIManager::FindPage(int PageId)
{
	std::map<int,PageData_t*>::iterator it=PageData.find(PageId);
	if (it!=PageData.end())
		return it->second;
	else
		return NULL;
}

int GUIManager::CreatePage()
{
	PageData_t* NewPage=new PageData_t;
	NewPage->Id=GenerateId();
	//创建空控件作为根节点，没有名字，不加入名字列表
	//除了ChildList，其余属性均无意义
	NewPage->Root=new CEmpty;
	NewPage->Root->Parent=NULL;
	NewPage->Root->Name=NULL;
	NewPage->Count=1;
	PageData.insert(std::make_pair(NewPage->Id,NewPage));
	//根节点不接收创建通知（如果以后需要在page创建后获得通知，可以加上）
	return NewPage->Id;
}

void GUIManager::DestroyPage(int PageId)
{
	PageData_t* Page=FindPage(PageId);
	if (Page!=NULL)
	{
		if (Page->Id==DisplayPage->Id)
		{
			//延迟操作，直到输入处理函数执行完时才执行，防止控件引用失效
			if (InProcessState)
			{
				DeferDeletePageId=PageId;
				PageWillDelete=TRUE;
				return ;
			}
			//如果删除当前显示页面，需要自行安排好下个展示页面
			//此外，还需要重置管理器输入状态，解除相关控件的引用
			ResetInputState();
			DisplayPage=NULL;
		}
		RecursiveDeleteControl(Page,Page->Root);
		PageData.erase(PageId);
		delete Page;
	}
}

void GUIManager::SetDisplayPage(int PageId)
{
	PageData_t* Page=FindPage(PageId);
	if (Page!=NULL)
	{
		if (Page==DisplayPage)
			return ;
		//延迟操作，直到输入处理函数执行完时才执行，防止控件引用失效
		if (InProcessState)
		{
			DeferDisplayPageId=PageId;
			PageWillChange=TRUE;
			return ;
		}
		ResetInputState();
		DisplayPage=Page;
	}
}

int GUIManager::GetControlPageId(UIControl* Control)
{
	std::map<int,PageData_t*>::iterator it;
	for (it=PageData.begin();it!=PageData.end();it++)
	{
		PageData_t* Page=it->second;
		std::map<WCHAR*,UIControl*,wstrless_t>::iterator it2=
			Page->NameMap.find(Control->Name);
		if (it2!=Page->NameMap.end())
		{
			//不同Page里的控件可以重名，最终以指针判定
			if (it2->second==Control)
				return Page->Id;
		}
	}
	return -1;
}

void GUIManager::RecursiveDeleteControl(PageData_t* Page,UIControl* Control)
{
	//注意控件在父节点的ChildList里有一个引用，调用者应该把目标控件从容器移出
	//如果操作当前显示页面，还要重置状态以清除控件引用
	DbgRecursiveNum++;

	if (Control->ChildList.size()>0)
	{
		std::list<UIControl*>::iterator it;
		for (it=Control->ChildList.begin();it!=Control->ChildList.end();it++)
			RecursiveDeleteControl(Page,*it);
		Control->ChildList.clear();
	}
	//子节点遍历完毕，处理自身
	//根节点不在名字列表里，也不接受删除通知（后续如果需要，可能会加上删除通知）
	if (Control->Name!=NULL)
	{
		Control->Notify(EvtUninit,(PVOID)0,(PVOID)0);
		Page->NameMap.erase(Control->Name);
	}
	delete Control;
	Page->Count--;
	DbgRecursiveNum--;
}

BOOL GUIManager::InsertControl(int PageId,UIControl* Parent,UIControl* Control)
{
	PageData_t* Page=FindPage(PageId);
	if (Page!=NULL)
	{
		//插入控件的name已经存在时，返回FALSE
		std::map<WCHAR*,UIControl*,wstrless_t>::iterator it=
			Page->NameMap.find(Control->Name);
		if (it!=Page->NameMap.end())
			return FALSE;
		//插入不影响当前显示页面，无需重置状态（是否有特例？）
		if (Parent==NULL)
			Parent=Page->Root;
		Parent->ChildList.push_back(Control);	//以插入顺序判定zorder
		Control->Parent=Parent;
		Page->NameMap.insert(std::make_pair(Control->Name,Control));
		Page->Count++;
		Control->Notify(EvtInit,(PVOID)0,(PVOID)0);
		return TRUE;
	}
	return FALSE;
}

BOOL GUIManager::DeleteControl(int PageId,WCHAR* Name)
{
	PageData_t* Page=FindPage(PageId);
	if (Page!=NULL)
	{
		UIControl* Control=FindControl(PageId,Name);
		if (Control!=NULL)
		{
			//删除可能会影响当前页面，需要重置状态
			if (Page->Id==DisplayPage->Id)
			{
				//延迟操作，直到输入处理函数执行完时才执行，防止控件引用失效
				//特别注意，由于不会立即删除，控件关系和索引不会变化，可能与其他UI系统不同
				if (InProcessState)
				{
					DeferDeleteControlPageId=PageId;
					DeferDeleteList.push_back(wstrdup(Name));
					return TRUE;
				}
				ResetInputState();
			}
			std::list<UIControl*>::iterator it;
			for (it=Control->Parent->ChildList.begin();it!=Control->Parent->ChildList.end();it++)
			{
				if ((*it)==Control)
				{
					//把自己从父节点的ChildList移除
					Control->Parent->ChildList.erase(it);
					RecursiveDeleteControl(Page,Control);
					return TRUE;
				}
			}
		}
	}
	return FALSE;
}

UIControl* GUIManager::FindControl(int PageId,WCHAR* Name)
{
	PageData_t* Page=FindPage(PageId);
	if (Page!=NULL)
	{
		std::map<WCHAR*,UIControl*,wstrless_t>::iterator it=
			Page->NameMap.find(Name);
		if (it!=Page->NameMap.end())
			return it->second;	
	}
	return NULL;
}

UIControl* GUIManager::MouseHitTest()
{
	//根据zorder设定，同层排在后面的控件更靠近顶端，会挡住其他控件
	//因此同层控件从后向前遍历，只取符合条件的第一个，无需递归
	//单个节点上从父到子遍历，取最顶端的命中的控件，总体是BFS

	//除了zorder，子控件会受到滚动条影响，需要计算视口映射
	//控件在父控件视口的坐标=控件局部坐标-父控件滚动距离
	//控件在程序窗口的坐标=父控件在窗口的坐标+控件在父控件视口的坐标
	//合起来是screen_y=child_y-viewpos_y+parent_y，将其与鼠标在窗口的位置对比

	//控件有3种情况：完全在父控件视口内，部分在父控件视口内，完全在父控件视口外
	//尤其是第二种情况，子控件的判定范围超出了父控件的可视范围，超出部分是否会影响判定结果？
	//然而无论哪一种情况，要检查子控件，首先要满足鼠标落在父控件范围内，与超出部分无关

	//topmost专属处理，不受父控件视口限制
	if (TopmostCtrl!=NULL)
	{
		int ScreenPosX;
		int ScreenPosY;
		BacktraceScreenPosition(TopmostCtrl,&ScreenPosX,&ScreenPosY);
		if (PointInRect(this->MouseX,this->MouseY,ScreenPosX,ScreenPosY,TopmostCtrl->Width,TopmostCtrl->Height))
		{
			//已规定topmost控件不会是Disable或Invisible状态
			return TopmostCtrl;
		}
	}

	BOOL Next=TRUE;
	UIControl* Current=DisplayPage->Root;
	std::list<UIControl*>::reverse_iterator rit;
	int BasePosX=0;
	int BasePosY=0;
	do 
	{
		Next=FALSE;
		for (rit=Current->ChildList.rbegin();rit!=Current->ChildList.rend();rit++)
		{
			UIControl* Child=*rit;
			//如果控件不可见，控件和其子控件均不参与判定
			if (Child->Visible==FALSE)
				continue;
			//已规定topmost控件没有子控件，在最开始先行处理
			if (Child==TopmostCtrl)
				continue;
			int ScreenPosX=Child->X-Current->ViewPosX+BasePosX;
			int ScreenPosY=Child->Y-Current->ViewPosY+BasePosY;
			if (PointInRect(this->MouseX,this->MouseY,ScreenPosX,ScreenPosY,Child->Width,Child->Height))
			{
				//如果控件不可用，其子控件也视为不可用状态
				//不响应输入，同时挡住底层控件，本次视为无效输入
				if (Child->Enable==FALSE)
					return NULL;
				Current=Child;
				BasePosX=ScreenPosX;
				BasePosY=ScreenPosY;
				Next=TRUE;
				break;
			}
		}
	} while (Next);
	if (Current==DisplayPage->Root)
		return NULL;
	return Current;
}

UIControl* GUIManager::ScrollHitTest()
{
	//总体与MouseHitTest类似，但可滚动控件上面可以覆盖一些子控件，不需要在最顶层

	//topmost专属处理，不受父控件视口限制
	if (TopmostCtrl!=NULL)
	{
		int ScreenPosX;
		int ScreenPosY;
		BacktraceScreenPosition(TopmostCtrl,&ScreenPosX,&ScreenPosY);
		if (PointInRect(this->MouseX,this->MouseY,ScreenPosX,ScreenPosY,TopmostCtrl->Width,TopmostCtrl->Height))
		{
			//已规定topmost控件不会是Disable或Invisible状态
			if (TopmostCtrl->Scrollable)
				return TopmostCtrl;
		}
	}

	UIControl* TopScrollableControl=NULL;
	BOOL Next=TRUE;
	UIControl* Current=DisplayPage->Root;
	std::list<UIControl*>::reverse_iterator rit;
	int BasePosX=0;
	int BasePosY=0;
	do 
	{
		Next=FALSE;
		for (rit=Current->ChildList.rbegin();rit!=Current->ChildList.rend();rit++)
		{
			UIControl* Child=*rit;
			if (Child->Visible==FALSE)
				continue;
			//已规定topmost控件没有子控件，在最开始先行处理
			if (Child==TopmostCtrl)
				continue;
			int ScreenPosX=Child->X-Current->ViewPosX+BasePosX;
			int ScreenPosY=Child->Y-Current->ViewPosY+BasePosY;
			if (PointInRect(this->MouseX,this->MouseY,ScreenPosX,ScreenPosY,Child->Width,Child->Height))
			{
				//子控件不可用时，由底层控件处理该事件
				if (Child->Enable==FALSE)
					return TopScrollableControl;
				if (Child->Scrollable)
					TopScrollableControl=Child;
				Current=Child;
				BasePosX=ScreenPosX;
				BasePosY=ScreenPosY;
				Next=TRUE;
				break;
			}
		}
	} while (Next);
	return TopScrollableControl;
}

void GUIManager::RecursiveDraw(UIControl* Current,int BasePosX,int BasePosY)
{
	//根据zorder设定，同级排在前面的控件逻辑上靠近底端，先绘制，被遮挡，从前往后遍历
	//每个节点从父到子遍历，子控件靠近顶端，遮挡父控件，使用DFS
	DbgRecursiveNum++;
	std::list<UIControl*>::iterator it;
	for (it=Current->ChildList.begin();it!=Current->ChildList.end();it++)
	{
		UIControl* Child=*it;
		//目标控件不可见，则其子节点也不可见，无需递归
		if (!Child->Visible)
			continue;
		//已规定topmost控件没有子控件，在最后专门处理
		if (Child==TopmostCtrl)
			continue;
		//如果控件全部在视口之外，无需绘制，同时控件的子节点也一定在视口外，无需递归
		//子左边大于父右边，子右边小于父左边，子上边大于父下边，子下边小于父上边
		//todo：这里跳过了相等时仅边缘重合的情况，也没处理边缘周围可能增加的特效部分
		if (Child->X-Current->ViewPosX>Current->Width ||
			Child->X+Child->Width-Current->ViewPosX<0 ||
			Child->Y-Current->ViewPosY>Current->Height ||
			Child->Y+Child->Height-Current->ViewPosY<0)
			continue;
		//通过父控件的窗口坐标，以及子控件在父控件中滚动后的位置，将子控件映射至窗口坐标
		int ScreenPosX=Child->X-Current->ViewPosX+BasePosX;
		int ScreenPosY=Child->Y-Current->ViewPosY+BasePosY;
		//子控件以其自身的局部坐标系绘制
		D2dMgr->SetOrigin(ScreenPosX,ScreenPosY);

		//限制子控件在其自身范围内绘制（d2d的视口变换已生效）
		//需要特别说明，子控件clip区域会受到父控件clip区域的影响
		//父控件设置原点，然后进行clip，子控件再设置原点，clip区域在屏幕上的位置不变，逻辑坐标自动调整
		//这是d2d api特性允许的，之后子控件进行clip，才以新的原点为基准
		//由于子节点的范围被限制在父节点之内，两者都是窗口坐标，clip区域也是两者的交叠区域
		D2dMgr->PushClip(0,0,Child->Width,Child->Height);

		//控件自身完成绘制，然后递归处理下一层
		//由于根节点无需绘制，每层调用视为控件本身已被绘制过
		Child->Draw();
		RecursiveDraw(Child,ScreenPosX,ScreenPosY);
		D2dMgr->PopClip();
	}
	DbgRecursiveNum--;
}

void GUIManager::ShrinkDrawingRect(int Left,int Top,int Width,int Height)
{
	//专用于组件绘制，临时调整绘制原点和Clip范围，使之缩小至组件区域
	//每绘制完一个组件，都需要调用RecoverDrawingRect()恢复控件原来的区域
	//由于必须成对使用，LastOriginX和LastOriginY不需要初始化
	LastOriginX=D2dMgr->OriginX;
	LastOriginY=D2dMgr->OriginY;
	D2dMgr->SetOrigin(LastOriginX+Left,LastOriginY+Top);
	D2dMgr->PushClip(0,0,Width,Height);
}

void GUIManager::RecoverDrawingRect()
{
	D2dMgr->PopClip();
	D2dMgr->SetOrigin(LastOriginX,LastOriginY);
}

void GUIManager::UpdateView()
{
	if (DisplayPage==NULL)
		return ;
	D2dMgr->ReadyPaint();
	D2dMgr->Clear(0xFFFFFFFF);
	D2dMgr->SetOrigin(0,0);
	D2dMgr->SetColor(0xFF000000);
	D2dMgr->SetImageOpacity(1.0f);
	RecursiveDraw(DisplayPage->Root,0,0);

	//topmost专属处理，不受父控件视口限制，且一定可见
	if (TopmostCtrl!=NULL)
	{
		int ScreenPosX;
		int ScreenPosY;
		BacktraceScreenPosition(TopmostCtrl,&ScreenPosX,&ScreenPosY);
		D2dMgr->SetOrigin(ScreenPosX,ScreenPosY);
		D2dMgr->PushClip(0,0,TopmostCtrl->Width,TopmostCtrl->Height);
		TopmostCtrl->Draw();
		D2dMgr->PopClip();
	}

	D2dMgr->SubmitPaint();
}

void GUIManager::UpdateFrame()
{
	if (!Freezed)
	{
		ResMgr->UpdateAllAnimationRFrame();
		UpdateView();

		//Update()接口仅更新当前显示页面的控件状态，不更新后台页面
		//一般是动画，特效之类的，如输入光标，即使丢帧也影响不大
		//禁止在Update()里添加移除控件，否则迭代器会失效
		if (DisplayPage!=NULL)
		{
			std::map<WCHAR*,UIControl*,wstrless_t>::iterator it;
			for (it=DisplayPage->NameMap.begin();it!=DisplayPage->NameMap.end();it++)
			{
				UIControl* Control=it->second;
				Control->Update();
			}
		}
	}
}

void GUIManager::ResizeView(int Width,int Height,BOOL Minimized)
{
	Freezed=Minimized;
	ClientWidth=Width;
	ClientHeight=Height;
}

void GUIManager::ResetInputState()
{
	if (PushedCtrl!=NULL)
	{
		PushedCtrl->Notify(EvtMouseUp,(PVOID)0,(PVOID)0);
		PushedCtrl->Pushed=FALSE;
		PushedCtrl=NULL;
	}
	if (FocusCtrl!=NULL)
	{
		FocusCtrl->Notify(EvtBlur,(PVOID)0,(PVOID)0);
		FocusCtrl=NULL;
	}
	if (HoveredCtrl!=NULL)
	{
		HoveredCtrl->Notify(EvtMouseLeave,(PVOID)0,(PVOID)0);
		HoveredCtrl->Hovered=FALSE;
		HoveredCtrl=NULL;
	}
	//topmost的重置应该由控件收到上述消息后，改变自身状态，主动取消
	//重置输入状态不生成click事件

	DragState=FALSE;
	DragBeginX=-1;
	DragBeginY=-1;

	POINT pt;
	GetCursorPos(&pt);
	ScreenToClient(D2dMgr->hWnd,&pt);
	MouseX=pt.x;
	MouseY=pt.y;

	//防止切入程序时按着某个键，错过识别时机
	KeyCtrlDown=((GetAsyncKeyState(VK_CONTROL)&0x8000)!=0);
	KeyShiftDown=((GetAsyncKeyState(VK_SHIFT)&0x8000)!=0);
}

void GUIManager::RecordInput(UINT WinMessage,PVOID Param1,PVOID Param2)
{
	if (WinMessage==WM_LBUTTONDOWN || WinMessage==WM_LBUTTONUP || WinMessage==WM_MOUSEMOVE)
	{
		//窗口缩放后，绘制系统会自动拉伸或压缩，但是输入的窗口坐标并不会按比例变化
		//由于使用整数坐标，调整窗口大小会略微损失鼠标精度
		int WinMouseX=(int)Param1;
		int WinMouseY=(int)Param2;
		MouseX=WinViewWidth*WinMouseX/ClientWidth;
		MouseY=WinViewHeight*WinMouseY/ClientHeight;
	}
	else if (WinMessage==WM_KEYDOWN)
	{
		int WinKey=(int)Param1;
		if (WinKey==VK_CONTROL)
			KeyCtrlDown=TRUE;
		else if (WinKey==VK_SHIFT)
			KeyShiftDown=TRUE;
	}
	else if (WinMessage==WM_KEYUP)
	{
		int WinKey=(int)Param1;
		if (WinKey==VK_CONTROL)
			KeyCtrlDown=FALSE;
		else if (WinKey==VK_SHIFT)
			KeyShiftDown=FALSE;
	}
}

void GUIManager::BacktraceScreenPosition(UIControl* Control,int* PosX,int* PosY)
{
	//正向定位控件需要递归遍历，但是逆向回溯简单的多
	//将每一层控件相对其父控件的位置累加起来，最终结果是控件在窗口上的坐标
	int TotalX=0;
	int TotalY=0;
	while (Control->Name!=NULL)
	{
		int PosXInParent=Control->X-Control->Parent->ViewPosX;
		int PosYInParent=Control->Y-Control->Parent->ViewPosY;
		TotalX+=PosXInParent;
		TotalY+=PosYInParent;
		Control=Control->Parent;
	}
	*PosX=TotalX;
	*PosY=TotalY;
}

BOOL GUIManager::TrySetTopmost(UIControl* Control,BOOL Enable)
{
	//topmost的设计是为了支持Droplist类控件的实现，总体并不优雅
	//为了减少可能出现的问题，要求控件：
	//1.不能存在子控件 2.必须先获得焦点 3.不能是Disable或Invisible状态 4.总尺寸小于窗口
	//设定topmost的时机一般是点击控件，需要弹出菜单时
	//管理器的实现里，鼠标正常按下时，先获得焦点，再EvtMouseDown，无需担心
	//取消的时机一般是EvtBlur（点击控件也有可能发生），此时仍持有焦点
	//这个专用的topmost通过特殊判断处理实现，无需要修改节点关系和重设坐标
	if (Enable)
	{
		//只允许存在一个置顶控件
		if (TopmostCtrl!=NULL)
			return FALSE;
		//控件必须先获取焦点
		if (Control!=FocusCtrl)
			return FALSE;
		if (!Control->Enable || !Control->Visible)
			return FALSE;
		if (Control->ChildList.size()!=0)
			return FALSE;
		TopmostCtrl=Control;
		return TRUE;
	}
	else
	{
		if (Control!=FocusCtrl)
			return FALSE;
		//这种情况应该属于bug
		//if (Control!=TopmostCtrl)
		//	return FALSE;
		TopmostCtrl=NULL;
		return TRUE;
	}
}

BOOL GUIManager::IsCtrlKeyDown()
{
	return KeyCtrlDown;
}

void GUIManager::GetMousePosForControl(UIControl* Control,int* X,int* Y)
{
	int CtrlX;
	int CtrlY;
	BacktraceScreenPosition(Control,&CtrlX,&CtrlY);
	if (X!=NULL)
		*X=MouseX-CtrlX;
	if (Y!=NULL)
		*Y=MouseY-CtrlY;
}


void GUIManager::BlurControl(UIControl* Control)
{
	if (FocusCtrl==Control)
	{
		FocusCtrl->Notify(EvtBlur,(PVOID)0,(PVOID)0);
		FocusCtrl=NULL;
	}
}

void GUIManager::DispatchInput(UINT WinMessage,PVOID Param1,PVOID Param2)
{
	RecordInput(WinMessage,Param1,Param2);
	if (DisplayPage==NULL)
		return ;
	
	//为了简化处理，鼠标按下时，会屏蔽鼠标滚轮和键盘按键的输入，可能有一些不合理之处

	//Push，Hover，Click，Focus是每个控件都存在的基本属性，由管理器负责处理
	//鼠标按下时，取消Hover，改变Focus，设置Push，发送MouseDown
	//鼠标抬起时，发送MouseUp，发送Click，取消Push，设置Hover（不会改变Focus）
	//理由是Focus才能接受输入，管理器先使之变成Push状态，最后发送鼠标事件（不知是否有潜在的问题）

	//BUG：禁止在事件处理函数里打开任何其他Windows窗口，否则输入处理过程被子窗口打断
	//此时会收到WM_ACTIVATE，导致输入状态重置，再次切回窗口时，继续执行上次未完成的过程，程序崩溃
	//与Windows机制有关，也可能是ResetInputState()的处理不够严谨，暂时无法解决

	InProcessState=TRUE;
	switch (WinMessage)
	{
	case WM_LBUTTONDOWN:
		{
			//假设之前没有控件被按下，否则是出了bug
			//if (PushedCtrl!=NULL)
			//	return ;
			UIControl* Control=MouseHitTest();
			if (Control!=NULL)
			{
				//Hover暂时取消，不触发leave事件
				if (HoveredCtrl!=NULL)
				{
					HoveredCtrl->Hovered=FALSE;
					HoveredCtrl=NULL;
				}
				//输入焦点切换
				if (FocusCtrl!=Control)
				{
					if (FocusCtrl!=NULL)
						FocusCtrl->Notify(EvtBlur,(PVOID)0,(PVOID)0);
					FocusCtrl=Control;
					FocusCtrl->Notify(EvtFocus,(PVOID)0,(PVOID)0);
				}
				//Push切换
				PushedCtrl=Control;
				PushedCtrl->Pushed=TRUE;
				//鼠标按下事件
				int CtrlScreenX=0;
				int CtrlScreenY=0;
				BacktraceScreenPosition(PushedCtrl,&CtrlScreenX,&CtrlScreenY);
				PushedCtrl->Notify(EvtMouseDown,PVOID(MouseX-CtrlScreenX),PVOID(MouseY-CtrlScreenY));
				//Drag事件相关
				DragState=FALSE;
				DragBeginX=MouseX;
				DragBeginY=MouseY;
			}
		}
		break;
	case WM_LBUTTONUP:
		{
			//如果没有控件被按下，忽略此次MouseUp消息
			//可能的原因有很多，比如上次点击的是Disable控件
			//或从别的窗口切换过来，或page里没有控件，等等

			//处于按下状态时，控件捕获所有鼠标消息，状态不会切换
			if (PushedCtrl!=NULL)
			{
				//鼠标抬起事件
				int CtrlScreenX=0;
				int CtrlScreenY=0;
				BacktraceScreenPosition(PushedCtrl,&CtrlScreenX,&CtrlScreenY);
				PushedCtrl->Notify(EvtMouseUp,PVOID(MouseX-CtrlScreenX),PVOID(MouseY-CtrlScreenY));
				//只对鼠标在范围内的情况发送Click
				if (PointInRect(MouseX,MouseY,CtrlScreenX,CtrlScreenY,PushedCtrl->Width,PushedCtrl->Height))
					PushedCtrl->Notify(EvtClick,(PVOID)0,(PVOID)0);
				//有Drag记录时，额外发送EvtDragEnd
				if (DragState)
				{
					PushedCtrl->Notify(EvtDragEnd,PVOID(MouseX-CtrlScreenX),PVOID(MouseY-CtrlScreenY));
					DragState=FALSE;
					DragBeginX=-1;
					DragBeginY=-1;
				}
				//取消Push状态并尝试恢复Hover状态
				HoveredCtrl=PushedCtrl;
				HoveredCtrl->Hovered=TRUE;
				PushedCtrl->Pushed=FALSE;
				PushedCtrl=NULL;
				//不满足Hover条件，发送leave事件，重设Hover控件
				if (!PointInRect(MouseX,MouseY,CtrlScreenX,CtrlScreenY,HoveredCtrl->Width,HoveredCtrl->Height))
				{
					HoveredCtrl->Notify(EvtMouseLeave,(PVOID)0,(PVOID)0);
					HoveredCtrl->Hovered=FALSE;
					HoveredCtrl=NULL;
					UIControl* Control=MouseHitTest();
					if (Control!=NULL)
					{
						HoveredCtrl=Control;
						HoveredCtrl->Hovered=TRUE;
						HoveredCtrl->Notify(EvtMouseHover,(PVOID)0,(PVOID)0);
					}
				}
			}
		}
		break;
	case WM_MOUSEMOVE:
		{
			//处于按下状态时，控件捕获所有鼠标消息，状态不会切换
			if (PushedCtrl!=NULL)
			{
				//记录拖拽
				if (!DragState)
					DragState=TRUE;
				//鼠标移动事件
				int CtrlScreenX=0;
				int CtrlScreenY=0;
				BacktraceScreenPosition(PushedCtrl,&CtrlScreenX,&CtrlScreenY);
				PushedCtrl->Notify(EvtMouseMove,PVOID(MouseX-CtrlScreenX),PVOID(MouseY-CtrlScreenY));
			}
			else
			{
				UIControl* Control=MouseHitTest();
				if (Control!=NULL)
				{
					//Hover控件切换
					if (HoveredCtrl!=Control)
					{
						if (HoveredCtrl!=NULL)
						{
							HoveredCtrl->Notify(EvtMouseLeave,(PVOID)0,(PVOID)0);
							HoveredCtrl->Hovered=FALSE;
							//HoveredCtrl=NULL;
						}
						HoveredCtrl=Control;
						HoveredCtrl->Hovered=TRUE;
						HoveredCtrl->Notify(EvtMouseHover,(PVOID)0,(PVOID)0);
					}
					//鼠标移动事件
					int CtrlScreenX=0;
					int CtrlScreenY=0;
					BacktraceScreenPosition(HoveredCtrl,&CtrlScreenX,&CtrlScreenY);
					HoveredCtrl->Notify(EvtMouseMove,PVOID(MouseX-CtrlScreenX),PVOID(MouseY-CtrlScreenY));
				}
				else
				{
					//移到Disable的控件上，或当前区域没有控件，取消Hover
					if (HoveredCtrl!=NULL)
					{
						HoveredCtrl->Notify(EvtMouseLeave,(PVOID)0,(PVOID)0);
						HoveredCtrl->Hovered=FALSE;
						HoveredCtrl=NULL;
					}
				}
			}
		}
		break;
	case WM_MOUSEWHEEL:
		{
			//鼠标按下时不生成滚轮事件
			//尽管其中可能存在有意义的操作，比如鼠标选择文本时，滚轮可以向下扩选
			if (PushedCtrl==NULL)
			{
				UIControl* Control=ScrollHitTest();
				if (Control!=NULL)
				{
					//有种特殊情况，受页面滚动影响，底层编辑框被顶层挡住，理论上只要没失去焦点，仍可输入
					//在浏览器里，视口会往回滚动，直到编辑框进入视口之内，但是本框架目前无法支持
					//为了减少复杂度，滚轮滚动时，直接切换输入焦点，给本次接收滚轮的控件
					if (FocusCtrl!=Control)
					{
						if (FocusCtrl!=NULL)
							FocusCtrl->Notify(EvtBlur,(PVOID)0,(PVOID)0);
						FocusCtrl=Control;
						FocusCtrl->Notify(EvtFocus,(PVOID)0,(PVOID)0);
					}
					Control->Notify(EvtMouseWheel,(PVOID)Param1,(PVOID)Param2);
					//滚轮事件往往意味着页面位置变化（也可能是控件内变化），但鼠标位置没变
					//两者位置相对变化等价于鼠标移动，需要生成MouseMove事件
					DispatchInput(EvtMouseMove,(PVOID)MouseX,(PVOID)MouseY);
				}
			}
		}
		break;
	case WM_KEYDOWN:
		//鼠标按下时不生成键盘事件
		if (PushedCtrl==NULL && FocusCtrl!=NULL)
		{
			//快捷键组合在按下第二个键时触发，无需等待抬起
			FocusCtrl->Notify(EvtKeyDown,(PVOID)Param1,(PVOID)KeyCtrlDown);
		}
		break;
	case WM_KEYUP:
		if (PushedCtrl==NULL && FocusCtrl!=NULL)
		{
			//键盘按下时会连续发送消息，KeyUp事件没什么用
			FocusCtrl->Notify(EvtKeyUp,(PVOID)Param1,(PVOID)KeyCtrlDown);
		}
		break;
	case WM_CHAR:
		//鼠标按下时不生成键盘事件
		if (PushedCtrl==NULL && FocusCtrl!=NULL)
		{
			//如果控件不支持输入字符，应该忽略此通知
			//按下快捷键组合时，如Ctrl+C，仍会收到WM_CHAR，但值为0x20以下的特殊字符
			//即使有意义的字符如\n，\t，\b，也必须屏蔽，控件应该在EvtKeyDown响应按键而不是解析字符
			if ((int)Param1>=0x20)
				FocusCtrl->Notify(EvtKeyInput,(PVOID)&Param1,(PVOID)1);
		}
		break;
	case WM_IME_STARTCOMPOSITION:
		{
			//光标位置是控件自身的状态，光标绘制受控件zorder影响
			//管理器仅负责处理Focus，不保存光标位置，也不绘制光标
			//输入法需要用到光标位置时向控件询问，转换成窗口坐标返回
			//如果控件不支持输入法，则不作处理，管理器返回默认值
			int* PtrX=(int*)Param1;
			int* PtrY=(int*)Param2;
			*PtrX=0;
			*PtrY=0;
			if (PushedCtrl==NULL && FocusCtrl!=NULL)
			{
				//返回1代表已处理，否则使用默认值
				if (FocusCtrl->Notify(EvtQueryImmPos,(PVOID)PtrX,(PVOID)PtrY))
				{
					int CtrlScreenX=0;
					int CtrlScreenY=0;
					BacktraceScreenPosition(FocusCtrl,&CtrlScreenX,&CtrlScreenY);
					*PtrX=*PtrX+CtrlScreenX;
					*PtrY=*PtrY+CtrlScreenY;
				}
			}
		}
		break;
	}
	InProcessState=FALSE;

	//延迟处理删除操作
	if (DeferDeleteList.size()!=0)
	{
		std::list<WCHAR*>::iterator it;
		for (it=DeferDeleteList.begin();it!=DeferDeleteList.end();it++)
		{
			WCHAR* Name=*it;
			DeleteControl(DeferDeleteControlPageId,Name);
			delete[] Name;
		}
		DeferDeleteList.clear();
	}
	if (PageWillDelete)
		DestroyPage(DeferDeletePageId);
	if (PageWillChange)
		SetDisplayPage(DeferDisplayPageId);
	PageWillDelete=FALSE;
	PageWillChange=FALSE;
	DeferDeletePageId=-1;
	DeferDisplayPageId=-1;
	DeferDeleteControlPageId=-1;
}

int GUIManager::ComponentMouseDispatch(UIControl* Control,UIEvent_t UIEvent,PVOID Param1,PVOID Param2)
{
	int HitIndex=-1;
	//组件数量固定，不会变化，以Visible控制是否使用
	int ComponentNum=Control->ComponentNum;
	UIComponent** SubCpnt=Control->SubCpnt;
	int MouseX=(int)Param1;
	int MouseY=(int)Param2;
	//组件以索引顺序决定zorder，有重叠时，索引靠后的组件在顶端
	for (int i=ComponentNum-1;i>=0;i--)
	{
		if (SubCpnt[i]->Visible)
		{
			if (PointInRect(MouseX,MouseY,SubCpnt[i]->X,SubCpnt[i]->Y,SubCpnt[i]->Width,SubCpnt[i]->Height))
			{
				if (SubCpnt[i]->Enable)
					HitIndex=i;
				break;
			}
		}
	}

	if (UIEvent==EvtMouseDown)
	{
		for (int i=0;i<ComponentNum;i++)
		{
			//鼠标按下时，当前Hit的组件变为Pushed，其余组件均清空Pushed；所有组件均清空Hovered
			//或是没有Hit组件，所有组件全部清空Pushed和Hovered，本体处理输入
			if (i==HitIndex)
			{
				SubCpnt[i]->Hovered=FALSE;
				SubCpnt[i]->Pushed=TRUE;
				//映射控件局部坐标至组件局部坐标
				SubCpnt[i]->Notify(EvtMouseDown,PVOID(MouseX-SubCpnt[i]->X),PVOID(MouseY-SubCpnt[i]->Y));
			}
			else
			{
				SubCpnt[i]->Hovered=FALSE;
				SubCpnt[i]->Pushed=FALSE;
			}
		}
	}
	else if (UIEvent==EvtMouseUp)
	{
		for (int i=0;i<ComponentNum;i++)
		{
			//至多只有一个组件是Pushed，否则是出了BUG
			if (SubCpnt[i]->Pushed)
			{
				//按下的组件Capture鼠标，即使没有Hit，也会截获消息；抬起后再根据Hit的组件设置状态
				//按下时的特殊情况，如果没有Hit组件，说明Hit中了控件本体，控件本体应该不处理消息，只设置状态
				//但是单个EvtMouseUp不会产生副作用，决定仍保持现有逻辑，让控件本体完整处理EvtMouseUp
				SubCpnt[i]->Notify(EvtMouseUp,PVOID(MouseX-SubCpnt[i]->X),PVOID(MouseY-SubCpnt[i]->Y));
				break;
			}
		}
		for (int i=0;i<ComponentNum;i++)
		{
			//鼠标抬起时，当前指向的组件变为Hovered，其余组件均清空Hovered；所有组件均清空Pushed
			//或是没有指向组件，所有组件全部清空Pushed和Hovered，本体处理输入
			if (i==HitIndex)
			{
				SubCpnt[i]->Pushed=FALSE;
				SubCpnt[i]->Hovered=TRUE;
			}
			else
			{
				SubCpnt[i]->Pushed=FALSE;
				SubCpnt[i]->Hovered=FALSE;
			}
		}
	}
	else if (UIEvent==EvtMouseMove)
	{
		for (int i=0;i<ComponentNum;i++)
		{
			//至多只有一个组件是Pushed，否则是出了BUG
			if (SubCpnt[i]->Pushed)
			{
				//按下的组件Capture鼠标，即使没有Hit，也会截获消息
				//鼠标按下期间，所有的Hover和Pushed都不会改变，控件本体也是一样
				//可以直接返回，并强制令返回值变为Hit命中，控件本体不再处理EvtMouseMove
				SubCpnt[i]->Notify(EvtMouseMove,PVOID(MouseX-SubCpnt[i]->X),PVOID(MouseY-SubCpnt[i]->Y));
				if (HitIndex!=-1)
					return HitIndex;
				return 0;
			}
		}
		//非Pushed的情况
		for (int i=0;i<ComponentNum;i++)
		{
			if (i==HitIndex)
			{
				SubCpnt[i]->Notify(EvtMouseMove,PVOID(MouseX-SubCpnt[i]->X),PVOID(MouseY-SubCpnt[i]->Y));
				SubCpnt[i]->Hovered=TRUE;
			}
			else
			{
				SubCpnt[i]->Hovered=FALSE;
			}	
		}
	}
	else if (UIEvent==EvtMouseLeave)
	{
		//收到EvtMouseLeave，鼠标一定不是Pushed状态，取消所有Hover
		for (int i=0;i<ComponentNum;i++)
		{
			SubCpnt[i]->Pushed=FALSE;
			SubCpnt[i]->Hovered=FALSE;
		}
	}

	//组件处于Disable状态，或未Hit中，返回-1，处理控件本体
	return HitIndex;
}







